{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "### Tensors\n",
    "\n",
    "Tensors 类似于 numpy 中的多维数组(ndarrays)，但它还可以用于 GPU 中实现计算的加速。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "import torch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个未初始化的 5*3 矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1.0469e-38, 1.0653e-38, 1.0469e-38],\n",
      "        [4.2246e-39, 1.0286e-38, 1.0653e-38],\n",
      "        [1.0194e-38, 8.4490e-39, 1.0469e-38],\n",
      "        [9.3674e-39, 9.9184e-39, 8.7245e-39],\n",
      "        [9.2755e-39, 8.9082e-39, 9.9184e-39]])\n"
     ]
    }
   ],
   "source": [
    "x=torch.empty(5,3)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个随机初始化的 5*3 矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[0.1780, 0.2503, 0.8082],\n",
      "        [0.0536, 0.6481, 0.4860],\n",
      "        [0.3106, 0.3809, 0.4659],\n",
      "        [0.0145, 0.2309, 0.6044],\n",
      "        [0.1172, 0.5343, 0.1187]])\n"
     ]
    }
   ],
   "source": [
    "rand_x = torch.rand(5,3)\n",
    "print(rand_x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个数值皆是 0，类型为 long 的矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[0, 0, 0],\n",
      "        [0, 0, 0],\n",
      "        [0, 0, 0],\n",
      "        [0, 0, 0],\n",
      "        [0, 0, 0]])\n"
     ]
    }
   ],
   "source": [
    "zero_x = torch.zeros(5,3,dtype=torch.long)\n",
    "print(zero_x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个 tensor，初始化方式是给定数值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tensor1=torch.tensor([5.5,3])\n",
    "print(tensor1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "根据已存在的 tensor 创建新的 tensor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tensor2 = tensor1.new_ones(5,3,dtype=torch.double)\n",
    "print(tensor2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "修改数值类型，但有相同的 size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tensor3 = torch.randn_like(tensor2,dtype=torch.float)\n",
    "print('tensor3:',tensor3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获取 tensor 的 size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(tensor3.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注意**： torch.Size 实际上是元组(tuple)类型，所以支持所有的元组操作"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Operations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "加法操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tensor4 = torch.rand(5,3)\n",
    "print('tensor3+tensor4=',tensor3+tensor4)\n",
    "print('tensor3+tensor4=',torch.add(tensor3,tensor4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "新声明一个 tensor 变量保存加法操作的结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "result=torch.empty(5,3)\n",
    "torch.add(tensor3,tensor4,out=result)\n",
    "print('add result=',result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "直接修改变量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "tensor3.add_(tensor4)\n",
    "print('tensor3=',tensor3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注意**：可以改变 tensor 变量的操作都带有一个后缀 `_`, 例如 x.copy_(y), x.t_() 都可以改变 x 变量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以用类似 numpy 的索引操作来访问 tensor 的某一维, 比如访问 tensor3 第一列数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "修改 tensor 大小，可以采用方法 `torch.view`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "x = torch.randn(4, 4)\n",
    "y = x.view(16)\n",
    "z = x.view(-1, 8)\n",
    "print(x.size(), y.size(), z.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果 tensor 仅有一个元素，可以采用 `.item()` 来获取类似 Python 中整数类型的数值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.randn(1)\n",
    "print(x)\n",
    "print(x.item())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Numpy\n",
    "\n",
    "tensor 和 numpy 的 array 相互转换，并且如果是在 cpu 上的操作，两者转换会共享内存，即改变一个变量同时也改变另一个。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Tensor to Numpy array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a= torch.ones(5)\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b=a.numpy()\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "看看改变其中一个变量，另一个变量的改变"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a.add_(1)\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Numpy Array to Torch Tensor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "a = np.ones(5)\n",
    "b = torch.from_numpy(a)\n",
    "np.add(a, 1, out=a)\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 CPU 上，除了 CharTensor 外，都支持和 Numpy 的 array 的互相转换"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### CUDA Tensors\n",
    "\n",
    "Tensors 可以通过采用 `.to` 方法来转换到不同设备上"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[ 0.7967, -0.5496,  2.8737,  2.3398],\n",
      "        [-0.6285,  0.1667,  1.9449, -0.7438],\n",
      "        [ 2.3947, -0.1886,  0.4515, -1.0694],\n",
      "        [ 0.2418,  0.6636,  0.5676,  0.2931]], device='cuda:0')\n",
      "tensor([[ 0.7967, -0.5496,  2.8737,  2.3398],\n",
      "        [-0.6285,  0.1667,  1.9449, -0.7438],\n",
      "        [ 2.3947, -0.1886,  0.4515, -1.0694],\n",
      "        [ 0.2418,  0.6636,  0.5676,  0.2931]], dtype=torch.float64)\n"
     ]
    }
   ],
   "source": [
    "\n",
    "if torch.cuda.is_available():\n",
    "    device = torch.device(\"cuda\")        \n",
    "    y = torch.ones_like(x, device=device)\n",
    "    x = x.to(device)                      \n",
    "    z = x + y\n",
    "    print(z)\n",
    "    print(z.to(\"cpu\", torch.double)) "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
